package com.xiaomaoguai.fcp.pre.kepler.redis.lock.service.impl;

import com.alibaba.fastjson.JSON;
import com.googlecode.aviator.AviatorEvaluator;
import com.xiaomaoguai.fcp.pre.kepler.redis.lock.service.LockKeyBuilder;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.api.HandlerContext;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @fileName: AviatorLockKeyBuilder.java
 * @author: WeiHui
 * @date: 2018/12/31 20:32
 * @version: v1.0.0
 * @since JDK 1.8
 */
public class AviatorLockKeyBuilder implements LockKeyBuilder {

	@Override
	public String builder(String[] definitionKeys, Method method, Object[] parameterValues) {
		List<String> lockKeys = getSpelDefinitionKeyByAv(definitionKeys, parameterValues);
		return StringUtils.join(lockKeys, ":");
	}

	/**
	 * 通过av表达式获取锁key
	 *
	 * @param definitionKeys  锁key表达式
	 * @param parameterValues 方法入参
	 * @return 锁key
	 */
	private List<String> getSpelDefinitionKeyByAv(String[] definitionKeys, Object[] parameterValues) {
		List<String> definitionKeyList = new ArrayList<>();
		Map<String, Object> context = null;
		for (Object parameterValue : parameterValues) {
			if (parameterValue instanceof HandlerContext) {
				HandlerContext<?> hc = (HandlerContext<?>) parameterValue;
				context = hc.getBuf().getContext();
			} else {
				if (context == null) {
					context = new HashMap<>(16);
				}
				if (parameterValue != null) {
					Map<String, Object> params = JSON.parseObject(JSON.toJSONString(parameterValue));
					context.putAll(params);
				}
			}
		}
		if (context != null) {
			for (String definitionKey : definitionKeys) {
				String key = parserAvExpression(definitionKey, context);
				definitionKeyList.add(key);
			}
		} else {
			throw new IllegalArgumentException("锁参数不能为空");
		}
		return definitionKeyList;
	}

	@SuppressWarnings("unchecked")
	private <T> T parserAvExpression(String el, Map<String, Object> convertParam) {
		return (T) AviatorEvaluator.execute(el, convertParam, true);
	}

}
